import sys
from os.path import join, exists
from HTMLTestRunner import HTMLTestRunner
from abc import ABCMeta, abstractmethod
import optparse
import os
from Config.RunConfig import RunConfig, Options


class AutotestsRunnerException(Exception):
    def __init__(self, *args, **kwargs):
        super(AutotestsRunnerException, self).__init__(*args, **kwargs)


class RunnerArgsValidationError(AutotestsRunnerException):
    def __init__(self, message):
        super(RunnerArgsValidationError, self).__init__(message)


class BaseAutotestsRunner(HTMLTestRunner):
    __metaclass__ = ABCMeta

    def __init__(self):
        super(BaseAutotestsRunner, self).__init__()
        self._requiredOptions = []
        self._optParser = optparse.OptionParser()
        self.setUpOptions()
        self._runOptions = None
        self._runArgs = None

    def outputDir(self):
        return self._runOptions.outputDir

    def addOption(self, *args, **kwargs):
        requiredFlag = 'required'
        if requiredFlag in kwargs and kwargs[requiredFlag]:
            self._requiredOptions.append(kwargs['dest'])
            kwargs.pop(requiredFlag)
        self._optParser.add_option(*args, **kwargs)

    def setUpOptions(self):
        self.addOption('-o', '--outputDir', type='string', dest='outputDir',
                       default=RunConfig().get(Options.AirBackup.workingDir), help='path for output files')

    def setUpStart(self):
        RunConfig().set(Options.AirBackup.workingDir, self.outputDir())

    @abstractmethod
    def testsSuite(self):
        pass

    def reportName(self):
        return "AutotestsResults.html"

    def reportTitle(self):
        return "Autotest Report"

    def startTests(self):
        self._parseArgs()
        self.setUpStart()

        self.title = self.reportTitle()
        outputDir = self.outputDir()
        if not exists(outputDir):
            os.makedirs(outputDir)
        with open(join(outputDir, self.reportName()), 'w') as reportFile:
            self.stream = reportFile
            self.run(self.testsSuite())

    def _validateArgs(self):
        for option in self._requiredOptions:
            if not getattr(self._runOptions, option):
                raise RunnerArgsValidationError("Error: option %s is required" % option)

    def _parseArgs(self):
        self._runOptions, self._runArgs = self._optParser.parse_args()
        try:
            self._validateArgs()
        except RunnerArgsValidationError, e:
            sys.exit(str(e))
